# coding=utf-8
import math, re
from conf.json_map import GIS_SRID

class GisTransform(object):
    """gis坐标转换类"""
    def __init__(self, old_srid, new_srid):
        """
        经纬度(谷歌高德):'wgs84'/  墨卡托:'webMercator'/ 火星坐标系(国测局):'gcj02'
        """
        self.pi = 3.1415926535897932384626  # π   精度比math.pi 还高一些
        self.ee = 0.00669342162296594323  # 偏心率平方
        self.a = 6378245.0  # 长半轴

        func_name = GIS_SRID.get(old_srid)+'_to_'+GIS_SRID.get(new_srid)
        if hasattr(self, func_name):
            self.transform_func = getattr(self, func_name)

        self.finally_type = GIS_SRID.get(new_srid)
        self.finally_srid = new_srid


    def _out_of_china(self, lng, lat):
        """
        判断是否在国内，不在国内不做偏移
        :param lng:
        :param lat:
        :return:
        """
        return not (lng > 73.66 and lng < 135.05 and lat > 3.86 and lat < 53.55)

    def _transformlat(self, lng, lat):
        ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + \
              0.1 * lng * lat + 0.2 * math.sqrt(math.fabs(lng))
        ret += (20.0 * math.sin(6.0 * lng * self.pi) + 20.0 *
                math.sin(2.0 * lng * self.pi)) * 2.0 / 3.0
        ret += (20.0 * math.sin(lat * self.pi) + 40.0 *
                math.sin(lat / 3.0 * self.pi)) * 2.0 / 3.0
        ret += (160.0 * math.sin(lat / 12.0 * self.pi) + 320 *
                math.sin(lat * self.pi / 30.0)) * 2.0 / 3.0
        return ret

    def _transformlng(self, lng, lat):
        ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + \
              0.1 * lng * lat + 0.1 * math.sqrt(math.fabs(lng))
        ret += (20.0 * math.sin(6.0 * lng * self.pi) + 20.0 *
                math.sin(2.0 * lng * self.pi)) * 2.0 / 3.0
        ret += (20.0 * math.sin(lng * self.pi) + 40.0 *
                math.sin(lng / 3.0 * self.pi)) * 2.0 / 3.0
        ret += (150.0 * math.sin(lng / 12.0 * self.pi) + 300.0 *
                math.sin(lng / 30.0 * self.pi)) * 2.0 / 3.0
        return ret

    def wgs84_to_webMercator(self, lon, lat):
        """wgs84坐标 转 墨卡托坐标"""
        x = lon*20037508.342789/180
        y = math.log(math.tan((90+lat)*self.pi/360))/(self.pi/180)
        y = y *20037508.34789/180
        return x, y

    def gcj02_to_webMercator(self, x, y):
        """火星转墨卡托"""
        wgs84_x, wgs84_y = self.gcj02_to_wgs84(x, y)
        webMercator_x, webMercator_y = self.wgs84_to_webMercator(wgs84_x, wgs84_y)
        return webMercator_x, webMercator_y

    def webMercator_to_webMercator(self, x, y):
        return x, y

    def webMercator_to_wgs84(self, x, y):
        """墨卡托坐标 转 wgs84坐标"""
        lon = x / 20037508.34 * 180
        lat = y / 20037508.34 * 180
        lat = 180 / self.pi * (2 * math.atan(math.exp(lat * self.pi / 180)) - self.pi / 2)
        return lon, lat

    def gcj02_to_wgs84(self, lng, lat):
        """
        GCJ02(火星坐标系)转GPS84
        :param lng:火星坐标系的经度
        :param lat:火星坐标系纬度
        :return:
        """
        if self._out_of_china(lng, lat):
            return lng, lat
        dlat = self._transformlat(lng - 105.0, lat - 35.0)
        dlng = self._transformlng(lng - 105.0, lat - 35.0)
        radlat = lat / 180.0 * self.pi
        magic = math.sin(radlat)
        magic = 1 - self.ee * magic * magic
        sqrtmagic = math.sqrt(magic)
        dlat = (dlat * 180.0) / ((self.a * (1 - self.ee)) / (magic * sqrtmagic) * self.pi)
        dlng = (dlng * 180.0) / (self.a / sqrtmagic * math.cos(radlat) * self.pi)
        mglat = lat + dlat
        mglng = lng + dlng
        new_x = lng * 2 - mglng
        new_y = lat * 2 - mglat
        return new_x, new_y

    def wgs84_to_gcj02(self, lng, lat):
        """
        WGS84转GCJ02(火星坐标系)
        :param lng:WGS84坐标系的经度
        :param lat:WGS84坐标系的纬度
        :return:
        """
        if self._out_of_china(lng, lat):  # 判断是否在国内
            return lng, lat
        dlat = self._transformlat(lng - 105.0, lat - 35.0)
        dlng = self._transformlng(lng - 105.0, lat - 35.0)
        radlat = lat / 180.0 * self.pi
        magic = math.sin(radlat)
        magic = 1 - self.ee * magic * magic
        sqrtmagic = math.sqrt(magic)
        dlat = (dlat * 180.0) / ((self.a * (1 - self.ee)) / (magic * sqrtmagic) * self.pi)
        dlng = (dlng * 180.0) / (self.a / sqrtmagic * math.cos(radlat) * self.pi)
        mglat = lat + dlat
        mglng = lng + dlng
        return mglng, mglat

    def webMercator_to_gcj02(self, x, y):
        """墨卡托转火星"""
        wgs84_x, wgs84_y = self.webMercator_to_wgs84(x, y)
        gcj02_x, gcj02_y = self.wgs84_to_gcj02(wgs84_x, wgs84_y)
        return gcj02_x, gcj02_y



class GoemTransform(object):
    """gis文本转换类
        如: POLYGON ((114.09538 22.62663,114.095389 22.626589))
    """
    def __init__(self, gis):
        """

        :param tools_func: 基本工具函数, 转换单个坐标 如 (x,y)>>>(x_new,y_new)
        """
        self.transform_func = gis.transform_func
        self.finally_srid = gis.finally_srid

    def transform_wkt_geom(self, wkt_geom, to_Z=False):
        '''转换文本中所有点的坐标系'''

        def change_date(m):
            x = m.group(1)
            y = m.group(2)

            if to_Z:
                z = '0'
            else:
                z = m.group(3)

            x, y = self.transform_func(float(x), float(y))
            result = '{0} {1} {2}'.format(x, y, z)

            return result

        str_list = wkt_geom.split(',')
        new_str_list = []
        for str in str_list:

            if to_Z:
                datepat = re.compile(r'([\d|.]+) ([\d|.]+)')
            else:
                datepat = re.compile(r'([\d|.]+) ([\d|.]+) ([\d|.]+)')

            new_text = datepat.sub(change_date, str)

            new_str_list.append(new_text)

        new_goem = ','.join(new_str_list)

        # def __map_func(gis_str):    # 空格隔开的数字 字符串 222 333 0  / 333 444
        #     gis = gis_str.split(' ')
        #     x, y = self.transform_func(float(gis[0]), float(gis[1]))    # 使用转换器转换 前两个数
        #     if len(gis) > 2:
        #         z = gis[2]
        #         new_gis_str = str(x) + ' ' + str(y) + ' ' + str(z)
        #     else:
        #         new_gis_str = str(x) + ' ' + str(y)
        #     return new_gis_str
        #
        # this_geo_type = wkt_geom.split(" ")[0]  # 取出类型 参考: POLYGON
        # z = ''
        # if wkt_geom.split(" ")[1] != 'Z':
        #     gis_text = wkt_geom.split(" ")[1]   # 参考:((114.09538 22.62663 0,114.095389 22.626589 0),(114.09538 22.62663 0,114.095389 33.626589 0))
        # else:
        #     z = 'Z'
        #     gis_text = wkt_geom.split(" ")[2]
        #
        # result = re.search(r'(\(+)([\d|\.|\s\,]+)(\)+)', gis_text).groups()
        #
        # start_str = result[0]   # ((
        # text_str = result[1]    # 114.09538 22.62663,114.095389 22.626589
        # end_str = result[2]     # ))
        #
        # gis_list = text_str.split(',')
        # new_gis_list = map(__map_func, gis_list)
        # new_text_str = ','.join(new_gis_list)
        #
        # new_text = this_geo_type + z + start_str + new_text_str + end_str
        return new_goem

    def _change_multi(self, type, text):
        '''转换成MULTI类型'''
        new_type = 'MULTI'+type
        text = '('+text+')'
        return new_type, text

    def get_finally_text(self, wkt_geom):
        to_Z = False    # 是否转3D
        this_geo_type = wkt_geom.split(" ")[0]  # 取出类型 参考: POLYGON
        gis_text = re.search(r'(\(.*)', wkt_geom).group()
        if wkt_geom.split(" ")[1] != 'Z':  # 如果是二维数组则转换成三维
            to_Z = True
        else:
            to_Z = False

        gis_text = self.transform_wkt_geom(gis_text, to_Z)  # 转换文本中的所有点的坐标系

        if this_geo_type.upper() == 'LINESTRING' or this_geo_type.upper() == 'POLYGON':     # 如果是这两个单数类型的 线和多面体
            this_geo_type, gis_text = self._change_multi(this_geo_type, gis_text)   # 改成复数类型 加括号

        new_wkt_geom = 'SRID=' + str(self.finally_srid) + ';' + this_geo_type + ' Z ' + gis_text
        return new_wkt_geom, this_geo_type

if __name__ == '__main__':
    # 测试
    # gis = GisTransform('gcj02', 'wgs84')
    # x, y = gis.transform_func(116.404, 39.915)
    # print(x, y)  # 预期 116.39775550083061, 39.91359571849836
    #
    # gis = GisTransform('wgs84', 'gcj02')
    # x, y = gis.transform_func(116.404, 39.915)
    # print(x, y)  # 预期 116.41024449916938, 39.91640428150164

    gis = GisTransform(-1, 3857)
    print(gis.transform_func(114.09538, 22.62663))
    # geom_trans = GoemTransform(gis)
    # this_geo_type, new_text = geom_trans.transform_wkt_geom('POLYGON ((114.09538 22.62663,114.095389 22.626589,114.095374 22.626544,114.095319 22.626443,114.095269 22.626411,114.095156 22.626376,114.095039 22.626367,114.094941 22.626376,114.094906 22.626397,114.094894 22.626438,114.094916 22.626567,114.094929 22.626835,114.094931 22.626863,114.094954 22.626877,114.094981 22.626874,114.095054 22.62684,114.095196 22.626736,114.09538 22.62663))')
    # new_goem,type = geom_trans.get_finally_text('LINESTRING Z (12696110.3058 2577584.4804 0,12696110.2594 2577589.48 0)')
    # new_goem,type = geom_trans.get_finally_text('POLYGON Z ((13035449.5797 3782263.7806 0,13035468.8414 3782262.0873 0,13035465.716 3782206.4075 0,13035467.0257 3782106.5079 0,13035465.9277 3782003.7568 0,13035450.6492 3781806.2961 0,13035434.4721 3781627.6286 0,13035428.5895 3781589.4051 0,13035414.1086 3781517.7672 0,13035395.9144 3781356.1549 0,13035377.2877 3781356.5783 0,13035449.5797 3782263.7806 0),(13035401.6428 3781520.5252 0,13035395.1517 3781416.6672 0,13035410.2021 3781518.3468 0,13035424.462 3781589.1934 0,13035430.5033 3781627.8932 0,13035444.973 3781806.4795 0,13035460.6889 3782003.598 0,13035460.3582 3782106.0846 0,13035458.0552 3782206.6569 0,13035401.6428 3781520.5252 0))')
    # new_goem,type = geom_trans.get_finally_text('LINESTRING (12696110.3058 2577584.4804,12696110.2594 2577589.48)')
    # # new_goem, type = geom_trans.get_finally_text('MULTILINESTRING (12696110.3058 2577584.4804,12696110.2594 2577589.48)')
    # # new_goem, type = geom_trans.get_finally_text('POINT Z (12696351.026 2577648.0691 0)')
    # # new_goem,type = geom_trans.get_finally_text('POLYGON ((114.09538 22.62663,114.095389 22.626589,114.095374 22.626544,114.095319 22.626443,114.095269 22.626411,114.095156 22.626376,114.095039 22.626367,114.094941 22.626376,114.094906 22.626397,114.094894 22.626438,114.094916 22.626567,114.094929 22.626835,114.094931 22.626863,114.094954 22.626877,114.094981 22.626874,114.095054 22.62684,114.095196 22.626736,114.09538 22.62663))')
    #
    #
    # print(new_goem)
    # print(type)